var url = require('url'),
	qst = require('querystring'),
	rest = require('restler'),
	userpass = 'admin:existe',
	uri = 'http://'+userpass+'@localhost:8080/exist/rest/db/proyecto',
	timeout = 30000;

function replaceAll(text, busca, reemplaza){
	while (text.toString().indexOf(busca) != -1)
		text = text.toString().replace(busca,reemplaza);
	return text;
}

function getSeed(request, response, query) {
	var ip = request.connection.remoteAddress,
		seed = false;
	function write(data) {
		console.log('- IP: ' + ip + ' | Semilla solicitada: ' + seed);
		response.writeHead(200, {'Content-Type': 'text/plain'});
		response.write(seed);
		response.end();
	}
	function parse_last(data) {
		var builder = require('xmlbuilder');
		if (parseInt(data['@']['exist:count']) > 0) {
			seed = parseInt(data.digit['@'].id) + 1;
			seed = seed + '';
		} else
			seed = '0';
		builder.begin('xupdate:modifications')
			.att('version', '1.0')
			.att('xmlns:xupdate', 'http://www.xmldb.org/xupdate')
			.ele('xupdate:append')
				.att('select', '/digits')
				.att('child', 'last()')
				.ele('xupdate:element')
					.att('name', 'digit')
					.ele('xupdate:attribute')
						.att('name', 'id')
						.txt(seed)
					.up()
					.ele('xupdate:element')
						.att('name', 'hex')
						.txt('none')
					.up()
					.ele('xupdate:element')
						.att('name', 'status')
						.txt('processed')
					.up()
					.ele('xupdate:element')
						.att('name', 'timestamp')
						.txt(query.timestamp)
					.up()
					.ele('xupdate:element')
						.att('name', 'ip')
						.txt(ip);
		options = {data:builder.toString()};
		rest.post(uri, options).on('complete', write);
	}
	function parse_processing(data) {
		for (var i in data.digit) {
			if (parseInt(query.timestamp) - parseInt(data.digit[i].timestamp) > timeout) {
				seed = data.digit[i]['@'].id;
				break;
			}
		}
		if (!seed) {
			options = {parser:rest.parsers.xml, query:{_wrap:'yes', _query:'//digit[last()]'}};
			rest.get(uri, options).on('complete', parse_last);
		} else {
			var builder = require('xmlbuilder');
			builder.begin('xupdate:modifications')
				.att('version', '1.0')
				.att('xmlns:xupdate', 'http://www.xmldb.org/xupdate')
				.ele('xupdate:update')
					.att('select', '//digit[@id="' + seed + '"]/timestamp')
					.txt(query.timestamp);
			options = {data:builder.toString()};
			rest.post(uri, options).on('complete', write);
		}
	}
	options = {parser:rest.parsers.xml, query:{_wrap:'yes', _query:'//digit[status="processing"]'}};
	rest.get(uri, options).on('complete', parse_processing);
}

function setSeed(request, response) {
	var ip = request.connection.remoteAddress,
		POST = '';
	function write(data, status) {
		var code = status.statusCode + '';
		console.log('- Guardado... ' + code);
		response.writeHead(200, {'Content-Type': 'text/plain'});
		response.write(code);
		response.end();
	}
	request.addListener('data', function(data) {
		POST += data;
	}).addListener('end', function() {
		var query = qst.parse(POST),
			builder = require('xmlbuilder');
		console.log('- IP: ' + ip + ' | Dígito calculado: ' + query.seed + ', ' + query.hex);
		builder.begin('xupdate:modifications')
			.att('version', '1.0')
			.att('xmlns:xupdate', 'http://www.xmldb.org/xupdate')
			.ele('xupdate:update')
				.att('select', '//digit[@id="' + query.seed + '"]/status')
				.txt('processed')
			.up()
			.ele('xupdate:update')
				.att('select', '//digit[@id="' + query.seed + '"]/hex')
				.txt(query.hex);
		options = {data:builder.toString()};
		rest.post(uri, options).on('complete', write);
	});
}

function statistics(request, response, query) {
	var ip = request.connection.remoteAddress,
		today = new Date, day = 86400000,
		days = parseInt(query.days)-1,
		_query = '', json = {ips:[], values:[]}, ptr = 0;
	if (days > 14) {
		console.log('- IP: ' + ip + ' | Estadísticas de demasiados días solicitadas...');
		response.writeHead(501, {'Content-Type': 'text/plain'});
		response.write('Not Implemented');
		response.end();
		return;
	}
	today = new Date(today.getFullYear(), today.getMonth(), today.getDate());
	var timestamp = new Date(today.getTime() - day*days).getTime(),
		timestamp1 = new Date(timestamp + day).getTime();
	function write() {
		var streamify = require('json-streamify').streamify;
		console.log('- IP: ' + ip + ' | Estadísticas solicitadas de ' + query.days + ' días');
		var str = '';
		streamify(json, function(data) {str += data;});
		response.writeHead(200, {'Content-Type': 'text/plain'});
		response.write(str);
		response.end();
	}
	function parseIP(data) {
		for (var i=0; i<=days; i++)
			if (days>0)
				json.values[i].value[json.ips[ptr]] = parseInt(data['exist:value'][i]['#']);
			else
				json.values[i].value[json.ips[ptr]] = parseInt(data['exist:value']['#']);
		ptr++;
		if (ptr < json.ips.length) {
			var new_query = replaceAll(_query, '0.0.0.0', json.ips[ptr]);
			options = {parser:rest.parsers.xml, query:{_wrap:'yes', _query:new_query, _howmany:query.days}};
			rest.get(uri, options).on('complete', parseIP);
		} else write();
	}
	function getIP(data) {
		var num = parseInt(data['@']['exist:count']);
		if (num > 0)
			for (var i=0; i<num; i++) json.ips[i] = data['exist:value'][i]['#'];
		else json.ips[0] = '0.0.0.0';
		var new_query = replaceAll(_query, '0.0.0.0', json.ips[ptr]);
		options = {parser:rest.parsers.xml, query:{_wrap:'yes', _query:new_query, _howmany:query.days}};
		rest.get(uri, options).on('complete', parseIP);
	}
	for (var i=0; i<=days; i++) {
		json.values[i] = {};
		json.values[i].day = new Date(timestamp).getDate() + '/' + (new Date(timestamp).getMonth() + 1);
		json.values[i].value = {};
		_query += 'count(//digit[timestamp>='+timestamp+' and timestamp<'+timestamp1+' and status="processed" and ip="0.0.0.0"])';
		timestamp = new Date(timestamp + day).getTime();;
		timestamp1 = new Date(timestamp1 + day).getTime();
		if (i<days) _query += ',';
	}
	options = {parser:rest.parsers.xml, query:{_wrap:'yes', _query:'distinct-values(//ip)'}};
	rest.get(uri, options).on('complete', getIP);
}

exports.handler = function (request, response) {
	if (request.method === 'GET') {
		var query = url.parse(request.url, true).query;
		if (query.request === 'seed') getSeed(request, response, query);
		else if (query.request === 'statistics') statistics(request, response, query);
	} else if (request.method === 'POST') setSeed(request, response);
};